#-*-coding:utf-8-*-
from fileoperate import FileOperate
from test import test
import random
'''
This module is used to compress the data by 255byte.first using Matrix and then use cursor
@author liuhucheng
14/05/2012 10:05
'''

class FinalCompress:
    '''
    Compress the data.
    '''
    def __init__(self):
        '''
        Init the varities!
        '''
        self.cols = 256
        self.length = 0 #record the length of the data
        self.content = [0 for col in range(self.cols)]

    def AddByte(self,In,loc):
        '''
        In is  a byte data.
        loc is the pos of the byte in the string
        Add a byte into the Matrix.
        '''
        loc1 = self.GetLoc(loc)
        if (self.content[ord(In)] == 0):
            self.content[ord(In)] = [loc1]
            self.length += 1
        else:
            self.content[ord(In)].append(loc1)
            self.length += 1

    def AddaByte(self,In,loc):
        '''
        In is  a byte data.
        loc is the pos of the byte in the string
        Add a byte into the Matrix.
        '''
        if (self.content[ord(In)] == 0):
            self.content[ord(In)] = [loc]
            self.length += 1
        else:
            self.content[ord(In)].append(loc)
            self.length += 1

    def GetLoc(self,loc):
        '''
        deal with the original locality.range from 0 to 255
        '''
        if loc <= 254:
            return loc + 1
        else:
            return None

    def GetOriginalLoc(self,loc):
        '''
        Get the original locality.
        '''
        return loc - 1

    def MatrixDataByPos(self,pos):
        '''
        Get the data by Pos
        '''
        return self.GetOriginalLoc(self.content[pos])

    def GetDataLength(self):
        '''
        Get the data length.
        '''
        return self.length

    def GetDataStr(self):
        '''
        Get the Matrix Data str.
        '''
        i = 0
        strData = ''   #the 0x00 is used to flage the str,is a control byte.the end of the block end up with two 0x00
        for i in range(self.cols):
            if self.content[i] != 0:
                #if i != 0:
                strData += chr(i)       #record the start data pos
                for j in self.content[i]:
                    strData += chr(j)
                strData += '\0'
            else:
                continue        #if the data is zero,it don't need recording
        strData += '\0'
        return strData

    def Encoding(self,ostr):
        '''
        encode the string ostr.
        '''
        readlen = 255           #encode 255 bytes a time.
        outstr = ''
        while ostr:
            if len(ostr) > readlen:
                kstr = ostr[0:readlen]
                ostr = ostr[readlen:]
            else:
                kstr = ostr
                ostr = ''       #the bytes don't suffice comparion with 255
            for i in enumerate(kstr,1):
                self.AddaByte(i[1],i[0])
            outstr += self.GetDataStr()
            self.__init__()
        return outstr

    def GetOriginData(self):
        '''
        Get The origin data
        '''
        odata = [0 for i in range(255)]
        for k in enumerate(self.content,0):
            if k[1] != 0:
                for j in k[1]:
                    c = self.GetOriginalLoc(j)
                    odata[c] = chr(k[0])
            else:
                continue
        return reduce(lambda x, y:x+y if y != 0 else x,odata,'')

    def ConsstructMatrixByStr(self,datastr):
        '''
        rebuilt the Matrix by DataStr
        '''
        self.__init__()
        if datastr[-2:] != '\0\0':
            return False    #the str is not a datastr
        else:
            self.__init__()
            lent = len(datastr)
            i = 0
            pos = 0
            while (i < lent):
                if i == 0:
                    pos = ord(datastr[i])  #record the first position
                    i += 1
                else:
                    if datastr[i] == '\0':
                        if datastr[i + 1] == '\0':
                            i += 2
                        else:
                            pos = ord(datastr[i + 1])
                            i += 2
                    else:
                        #print pos
                        if self.content[pos] == 0:
                            self.content[pos] = [ord(datastr[i])]  #not the first one
                        else:
                            self.content[pos].append(ord(datastr[i]))  #is the first one
                        self.length += 1
                        i += 1
        return True

    def Decoding(self,enstr):
        '''
        This module is used to get the origin data.
        '''
        outstr = ''
        while enstr:
            cpos = enstr.find('\0\0')       #
            kt = enstr[0:cpos + 2]
            if len(enstr) == cpos + 2:
                enstr = ''      #the end of the str
            else:
                enstr = enstr[cpos + 2:]        #slice the str by flags
            re = self.ConsstructMatrixByStr(kt)
            if re == False:
                return False
            else:
                #if the result is optical,program must recovery the 255 byte.
                cstr = self.GetOriginData()
                outstr += cstr
        return outstr

    def test(self):
        '''
        test This module!
        '''
        ntotal = 254
        i = 0
        while i < ntotal:
            c = chr(random.randint(0,255))
            self.AddByte(c,i)
            i += 1
        datastr = self.GetDataStr()
        print len(datastr)
        #print datastr
        k = FileOperate()
        sp = k.cur_file_path()
        k.WriteFileStr(sp + '/datastr.txt',datastr)
        k.WriteFileStr(sp + '/Matrix.txt',str(self.content))
        self.ConsstructMatrixByStr(datastr)
        k.WriteFileStr(sp + '/MatrixRec.txt',str(self.content))
        #print self.content

    def test1(self):
        '''
        test
        '''
        avf = open('p.txt','rb')
        c = avf.read()
        avf.close()

        k = self.Encoding(c)
        avf = open('fe.txt','wb')
        avf.write(k)
        avf.flush()
        avf.close()

        c = self.Decoding(k)
        avf = open('fd.txt','wb')
        avf.write(c)
        avf.flush()
        avf.close()

if __name__ == "__main__":
    c = FinalCompress()
    c.test1()

